using Mapster; // 引入Mapster库，用于对象映射

using MapsterMapper;

using System.Reflection; // 引入MapsterMapper库，提供IMapper接口

namespace Microsoft.Extensions.DependencyInjection; // 命名空间，表示该类属于Microsoft.Extensions.DependencyInjection

/// <summary>
/// 对象映射拓展类
/// </summary>
public static class ObjectMapperServiceCollectionExtensions
{
    /// <summary>
    /// 添加对象映射
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="assemblies">扫描的程序集</param>
    /// <returns></returns>
    public static IServiceCollection AddObjectMapper(this IServiceCollection services, params Assembly[] assemblies)
    {
        var config = TypeAdapterConfig.GlobalSettings; // 获取全局的TypeAdapterConfig配置对象

        if (assemblies != null && assemblies.Length > 0) config.Scan(assemblies); // 如果有传入的程序集，则扫描这些程序集以发现映射配置

        // 设置默认的映射配置
        config.Default
              .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase) // 设置名称匹配策略为忽略大小写
              .PreserveReference(true); // 保留引用类型，避免循环引用问题

        // 配置默认全局映射（忽略大小写敏感）
        config.Default
              .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase)
              .PreserveReference(true);

        services.AddSingleton(config); // 将配置对象注册为单例服务
        services.AddScoped<IMapper, ServiceMapper>(); // 将IMapper接口的实现类ServiceMapper注册为作用域服务

        return services; // 返回服务集合
    }

    /// <summary>
    /// 添加对象映射并配置自定义映射规则
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configAction">自定义配置操作</param>
    /// <param name="assemblies">扫描的程序集</param>
    /// <returns></returns>
    public static IServiceCollection AddObjectMapper(this IServiceCollection services, Action<TypeAdapterConfig> configAction, params Assembly[] assemblies)
    {
        var config = TypeAdapterConfig.GlobalSettings; // 获取全局的TypeAdapterConfig配置对象

        if (assemblies != null && assemblies.Length > 0) config.Scan(assemblies); // 如果有传入的程序集，则扫描这些程序集以发现映射配置

        // 设置默认的映射配置
        config.Default
              .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase) // 设置名称匹配策略为忽略大小写
              .PreserveReference(true); // 保留引用类型，避免循环引用问题

        // 应用自定义配置
        configAction?.Invoke(config);

        services.AddSingleton(config); // 将配置对象注册为单例服务
        services.AddScoped<IMapper, ServiceMapper>(); // 将IMapper接口的实现类ServiceMapper注册为作用域服务

        return services; // 返回服务集合
    }

    /// <summary>
    /// 验证所有映射配置是否正确
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="serviceProvider">可选的服务提供者，如果提供则使用它来获取TypeAdapterConfig</param>
    /// <returns>服务集合</returns>
    /// <exception cref="InvalidOperationException">如果TypeAdapterConfig未注册或验证失败时抛出</exception>
    public static IServiceCollection ValidateObjectMapperConfig(this IServiceCollection services, IServiceProvider serviceProvider = null)
    {
        try
        {
            // 使用全局配置而不是从服务提供者获取
            var config = TypeAdapterConfig.GlobalSettings;

            // 如果提供了服务提供者，尝试从中获取配置（它可能已经被自定义）
            if (serviceProvider != null)
            {
                try
                {
                    var configFromServices = serviceProvider.GetService<TypeAdapterConfig>();
                    if (configFromServices != null)
                    {
                        config = configFromServices;
                    }
                }
                catch (Exception)
                {
                    // 如果无法从服务提供者获取，继续使用全局配置
                }
            }

            // 编译所有映射规则
            config.Compile();
             
            return services;
        }
        catch (Exception ex)
        {
            // 更详细的异常信息
            throw new InvalidOperationException(
                "验证对象映射配置时发生错误。请确保所有映射规则都正确定义，" +
                "特别是检查源类型和目标类型之间的属性映射。详细信息: " + ex.Message, ex);
        }
    }
}